"""
任务数据模型

定义任务的基本信息和要求。
"""

from dataclasses import dataclass, field
from datetime import date
from typing import Optional, List, Set
from enum import Enum
from .resource import ResourceRole, SkillLevel


class TaskPriority(Enum):
    """任务优先级枚举"""
    VERY_LOW = 1
    LOW = 2
    MEDIUM = 3
    HIGH = 4
    VERY_HIGH = 5


class TaskStatus(Enum):
    """任务状态枚举"""
    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    ON_HOLD = "on_hold"
    CANCELLED = "cancelled"


@dataclass
class Task:
    """
    任务信息模型

    Attributes:
        task_id: 任务唯一标识符
        project_id: 所属项目ID
        task_name: 任务名称
        required_role: 所需主要角色
        required_skill_level: 所需技能等级
        estimated_hours: 预估工时
        start_date: 任务开始日期
        end_date: 任务结束日期
        dependency_tasks: 依赖任务ID列表
        priority: 任务优先级
        required_skills: 所需特定技能集合
        assigned_resource_id: 分配的资源ID（可选）
        actual_hours: 实际工时（可选）
        status: 任务状态
        description: 任务描述（可选）
        deliverables: 交付物描述（可选）
    """
    task_id: str
    project_id: str
    task_name: str
    required_role: ResourceRole
    required_skill_level: SkillLevel
    estimated_hours: float
    start_date: date
    end_date: date
    dependency_tasks: List[str] = field(default_factory=list)
    priority: TaskPriority = TaskPriority.MEDIUM
    required_skills: Set[str] = field(default_factory=set)
    assigned_resource_id: Optional[str] = None
    actual_hours: Optional[float] = None
    status: TaskStatus = TaskStatus.NOT_STARTED
    description: Optional[str] = None
    deliverables: Optional[str] = None

    def __post_init__(self):
        """数据验证"""
        if self.start_date > self.end_date:
            raise ValueError("任务开始日期不能晚于结束日期")

        if not self.task_id.strip():
            raise ValueError("任务ID不能为空")

        if not self.project_id.strip():
            raise ValueError("项目ID不能为空")

        if not self.task_name.strip():
            raise ValueError("任务名称不能为空")

        if self.estimated_hours <= 0:
            raise ValueError("预估工时必须大于0")

        if self.actual_hours is not None and self.actual_hours < 0:
            raise ValueError("实际工时不能为负数")

    @property
    def duration_days(self) -> int:
        """计算任务持续天数"""
        return (self.end_date - self.start_date).days + 1

    @property
    def hours_per_day(self) -> float:
        """计算每日平均工时"""
        return self.estimated_hours / max(1, self.duration_days)

    @property
    def is_assigned(self) -> bool:
        """检查任务是否已分配资源"""
        return self.assigned_resource_id is not None

    @property
    def is_completed(self) -> bool:
        """检查任务是否已完成"""
        return self.status == TaskStatus.COMPLETED

    @property
    def has_dependencies(self) -> bool:
        """检查任务是否有依赖"""
        return len(self.dependency_tasks) > 0

    def is_active_on_date(self, check_date: date) -> bool:
        """检查指定日期任务是否活跃"""
        return self.start_date <= check_date <= self.end_date

    def can_start_after_date(self, check_date: date) -> bool:
        """检查任务是否可以在指定日期后开始"""
        return self.start_date >= check_date

    def overlaps_with(self, other_task: 'Task') -> bool:
        """检查与其他任务是否有时间重叠"""
        return not (self.end_date < other_task.start_date or
                   self.start_date > other_task.end_date)

    def assign_resource(self, resource_id: str) -> None:
        """分配资源到任务"""
        self.assigned_resource_id = resource_id
        if self.status == TaskStatus.NOT_STARTED:
            self.status = TaskStatus.IN_PROGRESS

    def complete_task(self, actual_hours: Optional[float] = None) -> None:
        """完成任务"""
        self.status = TaskStatus.COMPLETED
        if actual_hours is not None:
            self.actual_hours = actual_hours

    def estimate_completion_rate(self) -> Optional[float]:
        """估算完成率（基于实际工时）"""
        if self.actual_hours is None:
            return None
        return min(1.0, self.actual_hours / self.estimated_hours)

    def to_dict(self) -> dict:
        """转换为字典格式"""
        return {
            'task_id': self.task_id,
            'project_id': self.project_id,
            'task_name': self.task_name,
            'required_role': self.required_role.value,
            'required_skill_level': self.required_skill_level.value,
            'estimated_hours': self.estimated_hours,
            'start_date': self.start_date.isoformat(),
            'end_date': self.end_date.isoformat(),
            'duration_days': self.duration_days,
            'hours_per_day': round(self.hours_per_day, 2),
            'dependency_tasks': self.dependency_tasks,
            'priority': self.priority.value,
            'required_skills': list(self.required_skills),
            'assigned_resource_id': self.assigned_resource_id,
            'actual_hours': self.actual_hours,
            'status': self.status.value,
            'description': self.description,
            'deliverables': self.deliverables,
            'is_assigned': self.is_assigned,
            'is_completed': self.is_completed,
            'has_dependencies': self.has_dependencies
        }

    @classmethod
    def from_dict(cls, data: dict) -> 'Task':
        """从字典创建任务实例"""
        # 处理日期字段
        if isinstance(data['start_date'], str):
            data['start_date'] = date.fromisoformat(data['start_date'])
        if isinstance(data['end_date'], str):
            data['end_date'] = date.fromisoformat(data['end_date'])

        # 处理枚举字段
        if 'required_role' in data and isinstance(data['required_role'], str):
            data['required_role'] = ResourceRole(data['required_role'])
        if 'required_skill_level' in data and isinstance(data['required_skill_level'], int):
            data['required_skill_level'] = SkillLevel(data['required_skill_level'])
        if 'priority' in data and isinstance(data['priority'], int):
            data['priority'] = TaskPriority(data['priority'])
        if 'status' in data and isinstance(data['status'], str):
            data['status'] = TaskStatus(data['status'])

        # 处理技能集合
        if 'required_skills' in data and isinstance(data['required_skills'], list):
            data['required_skills'] = set(data['required_skills'])

        # 移除计算字段
        computed_fields = ['duration_days', 'hours_per_day', 'is_assigned',
                          'is_completed', 'has_dependencies']
        for field in computed_fields:
            data.pop(field, None)

        return cls(**data)